--
-- Author: shunguo.chen
-- Date: 2018-04-18 14:36:27
--
-- GuideController
--

local GuideView = import("..views.GuideView")
local GuideRender = import("..views.renders.GuideRender")
local GuideFeatureView = import("..views.GuideFeatureView")

local fileName = string.getModeName(...)
local ClassRef = class(fileName, app.mvc.ControllerBase)

function ClassRef:ctor(data)
    self.super.ctor(self, data)
end

function ClassRef:init()
    self._model = app:getInst("GuideModel")

    -- 弱引导GuideRender缓存
    self._renderCache = {}
    setmetatable(self._renderCache, {__mode = "kv"})

    -- 新功能弹框id缓存
    self._funcIdCache = nil

    self._playerHandler = UD.player:onChanged(handler(self, self.updatePlayer))
    self._taskHandler = UD:onChanged("task", handler(self, self.updateTask))
    self._sideTaskHandler = UD:onChanged("sideTask", handler(self, self.updateSideTask))
end

function ClassRef:removeListeners()
    self.super.removeListeners(self)

    UD.player:unChanged(self._playerHandler)
    UD:unChanged(self._taskHandler)
end

function ClassRef:listEvent()
    return {
        "OnGameConnected",
        "checkGuide",
        "compGuide",
        "cancelGuide",
        "onFunctionOpen"
    }
end

function ClassRef:onEvent(eventName, ...)
    local data = ...
    if eventName == "OnGameConnected" then
        self._model:initData()
    elseif eventName == "checkGuide" then
        self._model:checkGuide(data)
    elseif eventName == "cancelGuide" then
        self._model:cancelGuide(...)
    elseif eventName == "compGuide" then
        self:compGuide(...)
    elseif eventName == "onFunctionOpen" then
        self:openFeatureView(data)
    end
end

-- guide Guide
-- params = {
--  scene = funcId,
--  sceneSelf = 方法执行主体,
--  getFunc = func,
--  nextFunc = func/nil,
-- }    触发数据
function ClassRef:openView(guide, params)
    if cc.isDead(self._view) then
        self._view = GuideView.new()
        self._view:onCloseView(handler(self, self.closeView))
        self._view:onClearView(handler(self, self.clearView))
        self._view:onOperate(handler(self, self.onOperate))
        self:addChild(self._view)
    else
        self._view:nodeReturn()

        -- remove cache
        for k,v in pairs(self._renderCache) do
            if v == self._view then
                self._renderCache[k] = nil
                break
            end
        end
    end

    -- 缓存避免重复触发
    self._renderCache[guide.id] = self._view
    -- dump(self._renderCache, "Guide._renderCache add")

    -- 主界面引导三个类型(主界面，快捷使用，主界面右下角提示)，为了减少干扰，desktop引导需要隐藏另外两个的ui
    -- 正常逻辑：desktopTip的可见性依赖于quickView的可见性，并且正好相反
    if guide:isDesktop() then
        local isQuickViewVisible = app:sendMsg("UIController", "isQuickUseViewVisible")
        app:sendMsg("UIController", "hideQuickView", true)
        if not isQuickViewVisible then
            UIHandler:setDesktopTipVisible(false)
        end
    end

    self._view:refresh(guide, params)
    self._view:show()
end
function ClassRef:closeView(data)
    if self._view then
        local guide = self._view:getGuide()
        self._renderCache[guide.id] = nil
        -- dump(self._renderCache, "Guide._renderCache remove")

        self._view:nodeReturn()
        self:removeChild(self._view, data)

        -- 主界面引导，恢复之前的隐藏
        -- 正常逻辑：desktopTip的可见性依赖于quickView的可见性，并且正好相反
        if guide:isDesktop() then
            app:sendMsg("UIController", "showQuickView")
            local isQuickViewVisible = app:sendMsg("UIController", "isQuickUseViewVisible")
            if not isQuickViewVisible then
                UIHandler:setDesktopTipVisible(true)
            end
        end
    end
end

function ClassRef:isInDesktopGuide()
    if cc.isAlive(self._view) then
        local guide = self._view:getGuide()
        return guide:isDesktop()
    end
    return false
end

function ClassRef:storyOver()
    if self._funcIdCache then
        self:openFeatureView(self._funcIdCache)
    end
end

-- funcId 功能id
function ClassRef:openFeatureView(funcId)
    local conf = GD:queryFeatureOnById(funcId)
    if conf.bubbletip and conf.bubbletip == "1" then
        if BattleManager:isBattle() or StoryManager:isEnterStoryMode() then
            -- 剧情和战斗中，缓存操作等结束再弹框

            self._funcIdCache = funcId
            DelayStack:pushToFront({name = "newFeature"})
        else
            self._funcIdCache = funcId
            UIHandler:removeUIForNewFeature()

            local view = GuideFeatureView.new()
            view:onCloseView(function(sender)
                -- 主动关闭才清空cache
                self._funcIdCache = nil
                UIHandler:removePopupUiByKey(sender:getViewName())
            end)
            view:onClearView(function()
                -- cache还在，需要添加 DelayStack
                if self._funcIdCache then
                    DelayStack:pushToFront({name = "newFeature"})
                end
            end)

            -- 在其他的弹出界面下层
            view:setLocalZOrder(-1)
            UIHandler:addPopupUi(view, view:getViewName())
            view:refresh(conf)
            view:show()
        end
    end
end

-------------------------------------------------------
-- 监测等级变化
function ClassRef:updatePlayer(name, old, new)
    if name == "level" then
        self._model:activateGuide(Enums.GuideActivateType.level, new)
    end
end

-- 监测新获得任务
function ClassRef:updateTask(tasks, op)
    if op == "insert" then
        self._model:activateGuide(Enums.GuideActivateType.mainTask, tasks)
    elseif op == "update" then
        self._model:onTaskComp(tasks)
    end
end

-- 监测新获得任务
function ClassRef:updateSideTask(taskId, op)
    self._model:onSideTaskComp(taskId)
end

-- 新激活的引导，试着去触发它（看是否有触发的环境），只触发主界面的引导
function ClassRef:tryToTriggerGuide(guide)
    -- print("Guide:tryToTriggerGuide", guide.id, guide:isDesktopType())

    if guide:isDesktopType() or guide:isMap() then
        local trigger = function()
            if guide:isDesktopType() then
                UIHandler:checkDesktopGuide()
            else
                MapManager:checkGuide()
            end
        end

        if guide.delay > 0 then
            -- 延迟触发
            scheduler.newCron(function()
                    trigger()
                end, guide.delay)
        else
            trigger()
        end
    end
end

-- 开始引导
-- guide 引导数据
-- params 触发数据
function ClassRef:triggerGuide(guide, params)
    -- print("Guide:triggerGuide", guide.id, BattleManager:isBattle(), StoryManager:isEnterStoryMode())
    -- 1. 剧情模式和战斗中不引导
    if BattleManager:isBattle() then return end
    if StoryManager:isEnterStoryMode() then return end

    -- print("Guide:triggerGuide", guide.id, self._renderCache[guide.id])
    -- 2. 已经在引导中了不引导
    if self._renderCache[guide.id] then return end

    -- 3. node的触发主体，在node被移除后不再进行引导
    local scene = params.scene
    -- 佣兵和地图不是node触发主体
    local isNotMap = Constant.FUNC_TYPE_MERCENARY~=scene
    local isNotPartner = Constant.FUNC_TYPE_MAP~=scene
    if isNotMap and isNotPartner then
        local sceneSelf = params.sceneSelf
        -- print("Guide:triggerGuide scene", scene, tolua.isnull(sceneSelf))
        if tolua.isnull(sceneSelf) then return end
    end

    local node
    if guide.triggerType == 1 then
        -- 指示ui
        local sceneSelf = params.sceneSelf
        local getFunc = params.getFunc
        node = executeFunc(getFunc, sceneSelf, guide.id, guide.triggerFuncId)

        -- print("Guide:triggerGuide node", guide.id, node)
        -- 找不到ui，返回
        if cc.isDead(node) then return end
    elseif guide.triggerType == 2 then
        -- 点击屏幕点，必定是模态
    elseif guide.triggerType == 3 then
        -- npc头顶，必定是非模态
        local sceneSelf = params.sceneSelf
        local getFunc = params.getFunc
        node = executeFunc(getFunc, sceneSelf, guide.id, guide.triggerNpcId)

        -- print("Guide:triggerGuide node", guide.id, node)
        if cc.isDead(node) then return end
    end

    -- print("Guide:triggerGuide")
    if guide:isModal() then
        -- 模态，禁用点击

        -- 开始引导之后，强制主角停下来。模拟点击停止，其他的方法没找到
        app:getLaunchCtl():endCharacterMove()

        self:openView(guide, params)
    else
        self:_nodeAddGuideRender(guide, params, node)
    end
end

-- node 添加弱引导 GuideRender
function ClassRef:_nodeAddGuideRender(guide, params, node)
    if cc.isDead(node) then return end
    local parent = node:getParent()
    local zOrder = node:getLocalZOrder()
    local rect = node:getBoundingBox()
    local posX = rect.x + rect.width/2
    local posY = rect.y + rect.height/2
    -- local worldPos = parent:convertToWorldSpace(cc.p(rect.x, rect.y))
    -- rect.x = worldPos.x
    -- rect.y = worldPos.y

    -- print("Guide:_nodeAddGuideRender", guide.id)
    -- dump(rect, "rect")

    local render = GuideRender.create()
    render:setPosition(posX, posY)
    render:setSelectRect(rect)
    parent:addChild(render, zOrder)
    render:setStartData(params)
    render:setData(guide)
    render:show()
    render:onNodeEvent("exit", function()
        self._renderCache[guide.id] = nil
    end)
    render:onBtnClick(function(sender)
            render:removeFromParent()
        end)

    self._renderCache[guide.id] = render

    -- dump(self._renderCache, "Guide._renderCache add")
end

-- 模态guide因为任务完成而被清理
function ClassRef:compTaskGuide(guide)
    local render = self._renderCache[guide.id]
    if cc.isAlive(render) then
        self:compGuide(guide, render:getStartData())
        if render.nodeReturn then
            render:nodeReturn()
        end
        render:removeFromParent()
    else
        self:compGuide(guide, {})
    end
end

-- 引导完成
-- guide 引导数据
-- params 触发数据
function ClassRef:compGuide(guide, params)
    self._renderCache[guide.id] = nil
    -- dump(self._renderCache, "Guide._renderCache remove")

    -- 116补丁，装备强化按钮点击的时候，隐藏tips
    if guide.id == 116 then
        UIHandler:hideFloatPanel()
    end

    self._model:reqCompGuide(guide.id, function(nextGuide)
        -- 触发后续引导
        -- print("Guide:triggerNextGuide", nextGuide.id)
        -- dump(nextGuide, "nextGuide")
        -- print("scene", params.scene)
        -- 缓一帧触发
        scheduler.newCron(function()
            if nextGuide then
                -- 有下一步，触发下一步
                if nextGuide:isDesktopType() or nextGuide:isMap() then
                    -- 是Desktop和Map，使用特殊触发
                    self:tryToTriggerGuide(nextGuide)
                else
                    -- 其他的情况，使用现有params触发
                    local sceneSelf = params.sceneSelf
                    local nextFunc = params.nextFunc
                    if nextFunc then
                        executeFunc(nextFunc, sceneSelf)
                    end
                end
            else
                -- 没有下一步，试图触发现有的引导
                self._model:tryToTriggerGuides()
            end
        end, 0)
    end)
end

-------------------------------------------------------
function ClassRef:onOperate(op, ...)
    -- print("GuideController:onOperate op = " .. op)
    if op == "compGuide" then

    end
end

return ClassRef
